﻿namespace Snipps.ViewModels.Filters
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Windows.Input;

    using GalaSoft.MvvmLight.Command;

    using Snipps.Controls;
    using Snipps.Core;
    using Snipps.Core.Entities;
    using Snipps.Infrastructure.Services;

    public class TagFilterViewModel : FilterViewModelBase
    {
        private readonly ISnippetsDataContext _snippetsDataContext;

        private readonly IThreadingService _threadingService;

        private Tag _newTag;

        public TagFilterViewModel(ISnippetsDataContext snippetsDataContext, IThreadingService threadingService)
        {
            RemoveItemCommand = new RelayCommand<RemoveItemEventArgs>(OnRemoveItem);
            _snippetsDataContext = snippetsDataContext;
            _threadingService = threadingService;
            FilterTags = new ObservableCollection<Tag>();

            FilterTags.CollectionChanged += FilterTags_CollectionChanged;

            _newTag = new Tag();
        }

        public ICommand RemoveItemCommand { get; private set; }

        public ObservableCollection<Tag> FilterTags { get; private set; }

        private void OnRemoveItem(RemoveItemEventArgs removeItemEventArgs)
        {
            var tag = removeItemEventArgs.RemovedItem as Tag;
            if (tag != null)
            {
                FilterTags.Remove(tag);
            }
        }

        private void FilterTags_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            {
                case NotifyCollectionChangedAction.Replace:
                case NotifyCollectionChangedAction.Move:
                case NotifyCollectionChangedAction.Remove:

                    StartFiltering();
                    break;
            }
        }

        public override void StartFiltering()
        {
            if (IsBusy)
            {
                return;
            }

            base.StartFiltering();
            Func<IList<Tag>> f = () => _snippetsDataContext.FilterTags(FilterText, FilterTags);
            cancelFilteringAction = _threadingService.QueueExecution(f, GetTagsAsyncEnd, ExceptionCallback);
        }

        private void ExceptionCallback(Exception obj)
        {
        }

        protected override void OnIsActiveChanged()
        {
            base.OnIsActiveChanged();

            if (!IsActive)
            {
                if (FilterText.Length > 0)
                {
                    FilterText = string.Empty;
                }

                StartFilterWhenActive = true;
            }
            else
            {
                if (StartFilterWhenActive)
                {
                    StartFiltering();
                }
            }
        }

        private void GetTagsAsyncEnd(IList<Tag> tags)
        {
            CompletionList.FilteredItems.Clear();
            _newTag = new Tag { Name = FilterText };

            if (!FilterTags.Contains(_newTag) && !string.IsNullOrEmpty(_newTag.Name) && tags.All(x => !x.Equals(_newTag)))
            {
                CompletionList.FilteredItems.Add(_newTag);
            }

            _threadingService.QueueExecution(
                () =>
                    {
                        foreach (var tag in tags)
                        {
                            CompletionList.FilteredItems.Add(tag);
                        }
                    }, 
                () =>
                    {
                        SelectBestMatchingItem();
                        IsBusy = false;
                    });
        }
    }
}